package com.titan.server.osgi.impl;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.apache.felix.framework.Felix;
import org.apache.felix.framework.util.FelixConstants;
import org.apache.felix.main.Main;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleException;

import edu.ccut.titan.service.HostActivator;

/**
 * 本类可以启动,关闭OSGI容器.<p>
 * 通过配置文件config.properties对OSGI容器进行配置;
 * 加载指定路径下的所有Osgi bundles;
 * <p>
 *
 * @author LeslieGu
 */
public class OSGiWebappLoader {

	private static final String PLUGIN_FILE = "plugins";
	
    private Felix felix = null;

    private HostActivator activator;

    private String configFileLocation;

    private String bundlesHomeLocation;

    private Map<String, String> configMap;

    public OSGiWebappLoader(String configFileLocation, String bundlesHomeLocation) {
        this.configFileLocation = configFileLocation;
        this.bundlesHomeLocation = bundlesHomeLocation;

        initalConfigMap();

        try {
            // Create host activator;
            this.activator = new HostActivator();
            List<BundleActivator> list = new ArrayList<BundleActivator>();
            list.add(this.activator);

            // Now create an instance of the framework with
            // our configuration properties and activator.
            this.felix = new Felix(configMap, list);

            // Now start Felix instance.
            this.felix.start();
        } catch (Exception ex) {
            System.err.println("Could not create framework: " + ex);
            ex.printStackTrace();
        }
    }

    public Bundle[] getBundles() {
        return this.activator.getBundleContext().getBundles();
    }

    public void shutdown() {
        try {
            //利用独立的线程确保OSGI容器关闭
            new Thread() {
                public void run() {
                    try {
                        felix.stop();
                    } catch (BundleException e) {
                        e.printStackTrace();
                    }
                }
            }.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void initalConfigMap() {
        this.configMap = new HashMap<String, String>();
        this.initalConfigMapFromProperties();
        this.initalAutoStartBundles();
    }

    private void initalAutoStartBundles() {
        int frameworkStartLevel = 1;

        try {
            frameworkStartLevel = Integer.parseInt(this.configMap.get(FelixConstants.FRAMEWORK_STARTLEVEL_PROP));
        } catch (NumberFormatException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

        int i = 1;
        String bundlesFileNames = null;
        for (; i < frameworkStartLevel; ++i) {
            bundlesFileNames = this.getBundlesFileNamesFromDirectory(this.bundlesHomeLocation + System.getProperty("file.separator") + i);

            if (bundlesFileNames != null) {
                this.configMap.put(FelixConstants.AUTO_START_PROP + "." + i, bundlesFileNames);
            }
        }
        
        //加载plugins文件夹下的Boundles
        bundlesFileNames = this.getBundlesFileNamesFromDirectory(this.bundlesHomeLocation + System.getProperty("file.separator") + PLUGIN_FILE);
        this.configMap.put(FelixConstants.AUTO_START_PROP + "." + i, bundlesFileNames);
    }

    private String getBundlesFileNamesFromDirectory(String directory) {
        File firstDir = new File(directory);
        if (firstDir.exists()) {
            File[] bundlesNames = firstDir.listFiles(new FileFilter() {
                public boolean accept(File pathname) {
                    return pathname.getName().endsWith(".jar");
                }
            });

            if (bundlesNames != null) {
                StringBuffer bundlesNamesBuffer = new StringBuffer();
                for (File bundlesName : bundlesNames) {
                    bundlesNamesBuffer.append("file:" + bundlesName.getPath() + " ");
                }

                return bundlesNamesBuffer.toString();
            }
        }

        return null;
    }

    @SuppressWarnings("unchecked")
	private void initalConfigMapFromProperties() {
        Properties configProperties = this.getConfigProperties(this.configFileLocation);

        Enumeration enumeration = configProperties.propertyNames();
        while (enumeration.hasMoreElements()) {
            String key = (String) enumeration.nextElement();
            configMap.put(key, Main.substVars(configProperties.getProperty(key), key, null, configProperties));
        }
    }

    private Properties getConfigProperties(String configPropertisLocation) {
        Properties properties = new Properties();

        try {
            properties.load(new FileInputStream(new File(configPropertisLocation)));
        } catch (IOException e) {
            e.printStackTrace();
        }

        return properties;
    }
}
